#define r 0.5
#define TMIN 0.1
#define TMAX 30.
#define RAYMARCH_TIME 128
#define PRECISION .0001
#define PI 3.1415926

vec2 fixUV(in vec2 uv) {
    // 将从0-1902的像素uv值，转换为 0~1的uv值。
    return (2. * uv - iResolution.xy ) / min(iResolution.xx, iResolution.yy);
}


float sdfPlane(in vec3 p) { 
    return p.y; 
}
float sdfSphere(in vec3 p) {
    vec3 pos = vec3(0., 1., 0.);
    return length(p - pos) - r;
}

float map(in vec3 p) {
    float d = sdfPlane(p);
    d = min(d, sdfSphere(p));
    return d;
}


float rayMarch(in vec3 ro, in vec3 rd) {
    // ro: 原点，出发点（可以取摄像机位置）
    // rd：前进方向，可取相机->物体的方向
    float t = TMIN; // 
    for(int i = 0; i < RAYMARCH_TIME; i++) {
        vec3 p = ro + t * rd; // 前进
        float d = map(p);
        if(d < PRECISION) { // 到达了，不穿过
            break;
        }
        t += d;
        if(t >= TMAX) break;
    }
    return t;
}

#define f map
vec3 calcNormal( in vec3  p) // for function f(p)
{
    const float h = 0.0001; // replace by an appropriate value
    const vec2 k = vec2(1,-1);
    return normalize( k.xyy*f( p + k.xyy*h ) + 
                      k.yyx*f( p + k.yyx*h ) + 
                      k.yxy*f( p + k.yxy*h ) + 
                      k.xxx*f( p + k.xxx*h ) );
}


mat3 setCamera(vec3 ta, vec3 ro, float cr) { // 动态计算相机位置，让相机可以旋转，方便调试
    vec3 z = normalize(ta - ro);
    vec3 cp = vec3(sin(cr), cos(cr), 0.);
    vec3 x = normalize(cross(z, cp));
    vec3 y = cross(x, z);
    return mat3(x, y, z);
}

void calcCamera(out vec3 ro, out vec3 rd, vec2 uv) {
    ro = vec3(0., 0., -1.5); // 起点位置，摄像机位置
    ro = vec3(2. * cos(iTime), 0.2 * cos(iTime * .5) + 3., 2. * sin(iTime)); // 旋转摄像头，方便观察
    if(iMouse.z > 0.01) { // 鼠标输入控制摄像头
        float theta = iMouse.x / iResolution.x * 2. * PI;
        ro = vec3(2. * cos(theta), .2 + 3., 2. * sin(theta));
    }
    vec3 ta = vec3(0.);
    mat3 cam = setCamera(ta, ro, 0.);


    rd = normalize(vec3(uv, 0.) - ro); // 相机到 各个屏幕像素的方向
    rd = normalize(cam * vec3(uv, 1.));
}


float softshadow( in vec3 ro, in vec3 rd, float k ) {
    float res = 1.0;
    for( float t = TMIN ; t < TMAX; )
    {
        float h = map(ro + rd * t);
        if( h< PRECISION )
            return 0.0;
        res = min( res, k * h / t );
        t += h;
    }
    return res;
}

float softshadow2( in vec3 ro, in vec3 rd, float k )
{
    float res = 1.0;
    float ph = 1e20;
    for( float t = TMIN; t < TMAX; )
    {
        float h = map(ro + rd * t);
        if( h<0.001 )
            return 0.0;
        float y = h * h / (2.0 * ph);
        float d = sqrt(h*h - y*y);
        res = min( res, k * d /max(0.0, t-y) );
        ph = h;
        t += h;
    }
    return res;
}

vec3 calcLight(vec3 p, vec3 normal, vec3 lightDirWS) {
    vec3 color = vec3(1.);

    float LdotN = dot(lightDirWS, normal);
    LdotN = clamp(LdotN, 0., 1.) ;
    float lambert = LdotN;
    


    vec3 amb = vec3(0.);
    amb = (.5 + .5 * dot(normal, vec3(0., 1., 0.)) ) * vec3(.25);

    float shadow = 1.;
    // 计算阴影
    // float shadowT = rayMarch(p, lightDirWS); // 从物体表面向光源方向 rayMarch

    float shadowT = softshadow2(p, lightDirWS, 40.);
    if(shadowT < TMAX) { // 碰到了物体, 那么就是被东西挡住了
        shadow = shadowT;
        // shadow = .3;
    }

    // if(lambert <= .5) shadow = 1.; // 防止物体本身，也计算本身的阴影

    color = color * lambert * shadow + amb;

    return color ;
}




vec3 render(vec2 uv) {
    vec3 ro = vec3(0.0);
    vec3 rd = vec3(0.0);
    calcCamera(ro, rd, uv);


    // vec3 lightWS = vec3(1., 2., 0.);
    vec3 lightWS = vec3(2., 3.,  1.);

    vec3 color = vec3(0., 0., 0.);
    float t = rayMarch(ro, rd);

    if(t < TMAX) {
        vec3 p = ro + t * rd; // 当前点位置，世界坐标
        vec3 lightDirWS = normalize(lightWS - p);
        vec3 normal = calcNormal(p);

        color = vec3(1., 1., 1.);
        color = calcLight(p, normal, lightDirWS) * color;

    }

    return color;
}

vec3 renderAA(in vec2 fragCoord) { // 4次采样，进行平滑反锯齿
    int AATime = 4;

    vec3 color = vec3(0.);

    color += render(fixUV(fragCoord + vec2(0, 0)));
    color += render(fixUV(fragCoord + vec2(0, 1)));
    color += render(fixUV(fragCoord + vec2(1, 0)));
    color += render(fixUV(fragCoord + vec2(0, -1)));
    color += render(fixUV(fragCoord + vec2(-1, 0)));

    return color / (float(AATime) + 1.);

}


void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fixUV(fragCoord);

    vec3 col = render(uv);
    col = renderAA(fragCoord);

    fragColor = vec4(col,1.0);
}